// Copyright Epic Games, Inc. All Rights Reserved.

#include "LyraCharacter.h"

#include "AbilitySystem/LyraAbilitySystemComponent.h"
#include "Camera/LyraCameraComponent.h"
#include "Character/LyraHealthComponent.h"
#include "Character/LyraPawnExtensionComponent.h"
#include "Components/CapsuleComponent.h"
#include "Components/SkeletalMeshComponent.h"
#include "LyraCharacterMovementComponent.h"
#include "LyraGameplayTags.h"
#include "LyraLogChannels.h"
#include "Net/UnrealNetwork.h"
#include "Player/LyraPlayerController.h"
#include "Player/LyraPlayerState.h"
#include "System/LyraSignificanceManager.h"
#include "TimerManager.h"

#include UE_INLINE_GENERATED_CPP_BY_NAME(LyraCharacter)

class AActor;
class FLifetimeProperty;
class IRepChangedPropertyTracker;
class UInputComponent;

static FName NAME_LyraCharacterCollisionProfile_Capsule(TEXT("LyraPawnCapsule")); // Lyra角色碰撞配置文件_胶囊体
static FName NAME_LyraCharacterCollisionProfile_Mesh(TEXT("LyraPawnMesh")); // Lyra角色碰撞配置文件_网格体

/**
 * 构造函数
 */
ALyraCharacter::ALyraCharacter(const FObjectInitializer& ObjectInitializer)
	: Super(ObjectInitializer.SetDefaultSubobjectClass<ULyraCharacterMovementComponent>(ACharacter::CharacterMovementComponentName))
{
	// 尽量避免角色tick
	PrimaryActorTick.bCanEverTick = false; // 主ActorTick永远不能tick
	PrimaryActorTick.bStartWithTickEnabled = false; // 主ActorTick开始时禁用

	SetNetCullDistanceSquared(900000000.0f); // 设置网络剔除距离平方

	UCapsuleComponent* CapsuleComp = GetCapsuleComponent(); // 获取胶囊体组件
	check(CapsuleComp); // 检查胶囊体组件
	CapsuleComp->InitCapsuleSize(40.0f, 90.0f); // 初始化胶囊体大小
	CapsuleComp->SetCollisionProfileName(NAME_LyraCharacterCollisionProfile_Capsule); // 设置碰撞配置文件名称

	USkeletalMeshComponent* MeshComp = GetMesh(); // 获取网格体组件
	check(MeshComp); // 检查网格体组件
	MeshComp->SetRelativeRotation(FRotator(0.0f, -90.0f, 0.0f));  // 旋转网格体使其X轴向前，因为导出时是Y轴向前
	MeshComp->SetCollisionProfileName(NAME_LyraCharacterCollisionProfile_Mesh); // 设置碰撞配置文件名称

	ULyraCharacterMovementComponent* LyraMoveComp = CastChecked<ULyraCharacterMovementComponent>(GetCharacterMovement()); // 获取Lyra角色移动组件
	LyraMoveComp->GravityScale = 1.0f; // 重力缩放
	LyraMoveComp->MaxAcceleration = 2400.0f; // 最大加速度
	LyraMoveComp->BrakingFrictionFactor = 1.0f; // 制动摩擦因子
	LyraMoveComp->BrakingFriction = 6.0f; // 制动摩擦
	LyraMoveComp->GroundFriction = 8.0f; // 地面摩擦
	LyraMoveComp->BrakingDecelerationWalking = 1400.0f; // 行走制动减速度
	LyraMoveComp->bUseControllerDesiredRotation = false; // 使用控制器期望旋转
	LyraMoveComp->bOrientRotationToMovement = false; // 朝向移动方向旋转
	LyraMoveComp->RotationRate = FRotator(0.0f, 720.0f, 0.0f); // 旋转速率
	LyraMoveComp->bAllowPhysicsRotationDuringAnimRootMotion = false; // 在动画根运动期间允许物理旋转
	LyraMoveComp->GetNavAgentPropertiesRef().bCanCrouch = true; // 导航代理属性：可以下蹲
	LyraMoveComp->bCanWalkOffLedgesWhenCrouching = true; // 下蹲时可以从边缘走下来
	LyraMoveComp->SetCrouchedHalfHeight(65.0f); // 设置下蹲半高

	PawnExtComponent = CreateDefaultSubobject<ULyraPawnExtensionComponent>(TEXT("PawnExtensionComponent")); // 创建Pawn扩展组件
	PawnExtComponent->OnAbilitySystemInitialized_RegisterAndCall(FSimpleMulticastDelegate::FDelegate::CreateUObject(this, &ThisClass::OnAbilitySystemInitialized)); // 注册并调用能力系统初始化委托
	PawnExtComponent->OnAbilitySystemUninitialized_Register(FSimpleMulticastDelegate::FDelegate::CreateUObject(this, &ThisClass::OnAbilitySystemUninitialized)); // 注册能力系统取消初始化委托

	HealthComponent = CreateDefaultSubobject<ULyraHealthComponent>(TEXT("HealthComponent")); // 创建健康组件
	HealthComponent->OnDeathStarted.AddDynamic(this, &ThisClass::OnDeathStarted); // 添加死亡开始动态委托
	HealthComponent->OnDeathFinished.AddDynamic(this, &ThisClass::OnDeathFinished); // 添加死亡结束动态委托

	CameraComponent = CreateDefaultSubobject<ULyraCameraComponent>(TEXT("CameraComponent")); // 创建相机组件
	CameraComponent->SetRelativeLocation(FVector(-300.0f, 0.0f, 75.0f)); // 设置相对位置

	bUseControllerRotationPitch = false; // 使用控制器俯仰旋转
	bUseControllerRotationYaw = true; // 使用控制器偏航旋转
	bUseControllerRotationRoll = false; // 使用控制器滚转旋转

	BaseEyeHeight = 80.0f; // 基础眼睛高度
	CrouchedEyeHeight = 50.0f; // 下蹲眼睛高度
}

/**
 * 预初始化组件
 */
void ALyraCharacter::PreInitializeComponents()
{
	Super::PreInitializeComponents(); // 调用父类方法
}

/**
 * 开始游戏
 */
void ALyraCharacter::BeginPlay()
{
	Super::BeginPlay(); // 调用父类方法

	UWorld* World = GetWorld(); // 获取世界

	const bool bRegisterWithSignificanceManager = !IsNetMode(NM_DedicatedServer); // 是否注册到重要性管理器
	if (bRegisterWithSignificanceManager) // 如果需要注册
	{
		if (ULyraSignificanceManager* SignificanceManager = USignificanceManager::Get<ULyraSignificanceManager>(World)) // 获取重要性管理器
		{
//@TODO: SignificanceManager->RegisterObject(this, (EFortSignificanceType)SignificanceType); // 注册对象
		}
	}
}

/**
 * 结束游戏
 */
void ALyraCharacter::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
	Super::EndPlay(EndPlayReason); // 调用父类方法

	UWorld* World = GetWorld(); // 获取世界

	const bool bRegisterWithSignificanceManager = !IsNetMode(NM_DedicatedServer); // 是否注册到重要性管理器
	if (bRegisterWithSignificanceManager) // 如果需要注册
	{
		if (ULyraSignificanceManager* SignificanceManager = USignificanceManager::Get<ULyraSignificanceManager>(World)) // 获取重要性管理器
		{
			SignificanceManager->UnregisterObject(this); // 取消注册对象
		}
	}
}

/**
 * 重置
 */
void ALyraCharacter::Reset()
{
	DisableMovementAndCollision(); // 禁用移动和碰撞

	K2_OnReset(); // 调用蓝图重置事件

	UninitAndDestroy(); // 取消初始化并销毁
}

/**
 * 获取生命周期复制属性
 */
void ALyraCharacter::GetLifetimeReplicatedProps(TArray< FLifetimeProperty >& OutLifetimeProps) const
{
	Super::GetLifetimeReplicatedProps(OutLifetimeProps); // 调用父类方法

	DOREPLIFETIME_CONDITION(ThisClass, ReplicatedAcceleration, COND_SimulatedOnly); // 复制加速度（仅模拟条件）
	DOREPLIFETIME(ThisClass, MyTeamID) // 复制我的团队ID
}

/**
 * 预复制
 */
void ALyraCharacter::PreReplication(IRepChangedPropertyTracker& ChangedPropertyTracker)
{
	Super::PreReplication(ChangedPropertyTracker); // 调用父类方法

	if (UCharacterMovementComponent* MovementComponent = GetCharacterMovement()) // 获取角色移动组件
	{
		// 压缩加速度：XY分量作为方向+幅度，Z分量作为直接值
		const double MaxAccel = MovementComponent->MaxAcceleration; // 最大加速度
		const FVector CurrentAccel = MovementComponent->GetCurrentAcceleration(); // 当前加速度
		double AccelXYRadians, AccelXYMagnitude; // XY弧度，XY幅度
		FMath::CartesianToPolar(CurrentAccel.X, CurrentAccel.Y, AccelXYMagnitude, AccelXYRadians); // 笛卡尔坐标转极坐标

		ReplicatedAcceleration.AccelXYRadians   = FMath::FloorToInt((AccelXYRadians / TWO_PI) * 255.0);     // [0, 2PI] -> [0, 255]
		ReplicatedAcceleration.AccelXYMagnitude = FMath::FloorToInt((AccelXYMagnitude / MaxAccel) * 255.0);	// [0, MaxAccel] -> [0, 255]
		ReplicatedAcceleration.AccelZ           = FMath::FloorToInt((CurrentAccel.Z / MaxAccel) * 127.0);   // [-MaxAccel, MaxAccel] -> [-127, 127]
	}
}

/**
 * 通知控制器改变
 */
void ALyraCharacter::NotifyControllerChanged()
{
	const FGenericTeamId OldTeamId = GetGenericTeamId(); // 获取旧团队ID

	Super::NotifyControllerChanged(); // 调用父类方法

	// 根据控制器更新我们的团队ID
	if (HasAuthority() && (GetController() != nullptr)) // 如果有权限且控制器不为空
	{
		if (ILyraTeamAgentInterface* ControllerWithTeam = Cast<ILyraTeamAgentInterface>(GetController())) // 获取带团队的控制器接口
		{
			MyTeamID = ControllerWithTeam->GetGenericTeamId(); // 设置我的团队ID
			ConditionalBroadcastTeamChanged(this, OldTeamId, MyTeamID); // 条件广播团队改变
		}
	}
}

/**
 * 获取Lyra玩家控制器
 */
ALyraPlayerController* ALyraCharacter::GetLyraPlayerController() const
{
	return CastChecked<ALyraPlayerController>(GetController(), ECastCheckedType::NullAllowed); // 转换为Lyra玩家控制器
}

/**
 * 获取Lyra玩家状态
 */
ALyraPlayerState* ALyraCharacter::GetLyraPlayerState() const
{
	return CastChecked<ALyraPlayerState>(GetPlayerState(), ECastCheckedType::NullAllowed); // 转换为Lyra玩家状态
}

/**
 * 获取Lyra能力系统组件
 */
ULyraAbilitySystemComponent* ALyraCharacter::GetLyraAbilitySystemComponent() const
{
	return Cast<ULyraAbilitySystemComponent>(GetAbilitySystemComponent()); // 转换为Lyra能力系统组件
}

/**
 * 获取能力系统组件
 */
UAbilitySystemComponent* ALyraCharacter::GetAbilitySystemComponent() const
{
	if (PawnExtComponent == nullptr) // 如果Pawn扩展组件为空
	{
		return nullptr; // 返回空
	}

	return PawnExtComponent->GetLyraAbilitySystemComponent(); // 返回Lyra能力系统组件
}

/**
 * 能力系统初始化时调用
 */
void ALyraCharacter::OnAbilitySystemInitialized()
{
	ULyraAbilitySystemComponent* LyraASC = GetLyraAbilitySystemComponent(); // 获取Lyra能力系统组件
	check(LyraASC); // 检查Lyra能力系统组件

	HealthComponent->InitializeWithAbilitySystem(LyraASC); // 用能力系统初始化健康组件

	InitializeGameplayTags(); // 初始化游戏标签
}

/**
 * 能力系统取消初始化时调用
 */
void ALyraCharacter::OnAbilitySystemUninitialized()
{
	HealthComponent->UninitializeFromAbilitySystem(); // 从能力系统取消初始化健康组件
}

/**
 * 被控制器拥有时调用
 */
void ALyraCharacter::PossessedBy(AController* NewController)
{
	const FGenericTeamId OldTeamID = MyTeamID; // 获取旧团队ID

	Super::PossessedBy(NewController); // 调用父类方法

	PawnExtComponent->HandleControllerChanged(); // 处理控制器改变

	// 获取当前团队ID并监听未来变化
	if (ILyraTeamAgentInterface* ControllerAsTeamProvider = Cast<ILyraTeamAgentInterface>(NewController)) // 获取作为团队提供者的控制器
	{
		MyTeamID = ControllerAsTeamProvider->GetGenericTeamId(); // 设置我的团队ID
		ControllerAsTeamProvider->GetTeamChangedDelegateChecked().AddDynamic(this, &ThisClass::OnControllerChangedTeam); // 添加团队改变动态委托
	}
	ConditionalBroadcastTeamChanged(this, OldTeamID, MyTeamID); // 条件广播团队改变
}

/**
 * 取消拥有时调用
 */
void ALyraCharacter::UnPossessed()
{
	AController* const OldController = GetController(); // 获取旧控制器

	// 停止监听旧控制器的变化
	const FGenericTeamId OldTeamID = MyTeamID; // 获取旧团队ID
	if (ILyraTeamAgentInterface* ControllerAsTeamProvider = Cast<ILyraTeamAgentInterface>(OldController)) // 获取作为团队提供者的控制器
	{
		ControllerAsTeamProvider->GetTeamChangedDelegateChecked().RemoveAll(this); // 移除所有团队改变委托
	}

	Super::UnPossessed(); // 调用父类方法

	PawnExtComponent->HandleControllerChanged(); // 处理控制器改变

	// 确定之后新的团队ID应该是什么
	MyTeamID = DetermineNewTeamAfterPossessionEnds(OldTeamID); // 确定拥有结束后的新团队ID
	ConditionalBroadcastTeamChanged(this, OldTeamID, MyTeamID); // 条件广播团队改变
}

/**
 * 控制器复制时调用
 */
void ALyraCharacter::OnRep_Controller()
{
	Super::OnRep_Controller(); // 调用父类方法

	PawnExtComponent->HandleControllerChanged(); // 处理控制器改变
}

/**
 * 玩家状态复制时调用
 */
void ALyraCharacter::OnRep_PlayerState()
{
	Super::OnRep_PlayerState(); // 调用父类方法

	PawnExtComponent->HandlePlayerStateReplicated(); // 处理玩家状态复制
}

/**
 * 设置玩家输入组件
 */
void ALyraCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
	Super::SetupPlayerInputComponent(PlayerInputComponent); // 调用父类方法

	PawnExtComponent->SetupPlayerInputComponent(); // 设置玩家输入组件
}

/**
 * 初始化游戏标签
 */
void ALyraCharacter::InitializeGameplayTags()
{
	// 清除可能残留在能力系统上的来自先前Pawn的标签
	if (ULyraAbilitySystemComponent* LyraASC = GetLyraAbilitySystemComponent()) // 获取Lyra能力系统组件
	{
		for (const TPair<uint8, FGameplayTag>& TagMapping : LyraGameplayTags::MovementModeTagMap) // 遍历移动模式标签映射
		{
			if (TagMapping.Value.IsValid()) // 如果标签有效
			{
				LyraASC->SetLooseGameplayTagCount(TagMapping.Value, 0); // 设置松散游戏标签计数为0
			}
		}

		for (const TPair<uint8, FGameplayTag>& TagMapping : LyraGameplayTags::CustomMovementModeTagMap) // 遍历自定义移动模式标签映射
		{
			if (TagMapping.Value.IsValid()) // 如果标签有效
			{
				LyraASC->SetLooseGameplayTagCount(TagMapping.Value, 0); // 设置松散游戏标签计数为0
			}
		}

		ULyraCharacterMovementComponent* LyraMoveComp = CastChecked<ULyraCharacterMovementComponent>(GetCharacterMovement()); // 获取Lyra角色移动组件
		SetMovementModeTag(LyraMoveComp->MovementMode, LyraMoveComp->CustomMovementMode, true); // 设置移动模式标签
	}
}

/**
 * 获取拥有的游戏标签
 */
void ALyraCharacter::GetOwnedGameplayTags(FGameplayTagContainer& TagContainer) const
{
	if (const ULyraAbilitySystemComponent* LyraASC = GetLyraAbilitySystemComponent()) // 获取Lyra能力系统组件
	{
		LyraASC->GetOwnedGameplayTags(TagContainer); // 获取拥有的游戏标签
	}
}

/**
 * 检查是否匹配指定的游戏标签
 */
bool ALyraCharacter::HasMatchingGameplayTag(FGameplayTag TagToCheck) const
{
	if (const ULyraAbilitySystemComponent* LyraASC = GetLyraAbilitySystemComponent()) // 获取Lyra能力系统组件
	{
		return LyraASC->HasMatchingGameplayTag(TagToCheck); // 返回是否匹配游戏标签
	}

	return false; // 返回false
}

/**
 * 检查是否匹配所有指定的游戏标签
 */
bool ALyraCharacter::HasAllMatchingGameplayTags(const FGameplayTagContainer& TagContainer) const
{
	if (const ULyraAbilitySystemComponent* LyraASC = GetLyraAbilitySystemComponent()) // 获取Lyra能力系统组件
	{
		return LyraASC->HasAllMatchingGameplayTags(TagContainer); // 返回是否匹配所有游戏标签
	}

	return false; // 返回false
}

/**
 * 检查是否匹配任何指定的游戏标签
 */
bool ALyraCharacter::HasAnyMatchingGameplayTags(const FGameplayTagContainer& TagContainer) const
{
	if (const ULyraAbilitySystemComponent* LyraASC = GetLyraAbilitySystemComponent()) // 获取Lyra能力系统组件
	{
		return LyraASC->HasAnyMatchingGameplayTags(TagContainer); // 返回是否匹配任何游戏标签
	}

	return false; // 返回false
}

/**
 * 掉出世界时调用
 */
void ALyraCharacter::FellOutOfWorld(const class UDamageType& dmgType)
{
	HealthComponent->DamageSelfDestruct(/*bFellOutOfWorld=*/ true); // 伤害自毁（掉出世界）
}

/**
 * 开始死亡时调用
 */
void ALyraCharacter::OnDeathStarted(AActor*)
{
	DisableMovementAndCollision(); // 禁用移动和碰撞
}

/**
 * 死亡完成时调用
 */
void ALyraCharacter::OnDeathFinished(AActor*)
{
	GetWorld()->GetTimerManager().SetTimerForNextTick(this, &ThisClass::DestroyDueToDeath); // 设置下一tick的定时器用于销毁
}

/**
 * 禁用移动和碰撞
 */
void ALyraCharacter::DisableMovementAndCollision()
{
	if (GetController()) // 如果有控制器
	{
		GetController()->SetIgnoreMoveInput(true); // 设置忽略移动输入
	}

	UCapsuleComponent* CapsuleComp = GetCapsuleComponent(); // 获取胶囊体组件
	check(CapsuleComp); // 检查胶囊体组件
	CapsuleComp->SetCollisionEnabled(ECollisionEnabled::NoCollision); // 设置碰撞启用为无碰撞
	CapsuleComp->SetCollisionResponseToAllChannels(ECR_Ignore); // 设置对所有通道的碰撞响应为忽略

	ULyraCharacterMovementComponent* LyraMoveComp = CastChecked<ULyraCharacterMovementComponent>(GetCharacterMovement()); // 获取Lyra角色移动组件
	LyraMoveComp->StopMovementImmediately(); // 立即停止移动
	LyraMoveComp->DisableMovement(); // 禁用移动
}

/**
 * 由于死亡而销毁
 */
void ALyraCharacter::DestroyDueToDeath()
{
	K2_OnDeathFinished(); // 调用蓝图死亡完成事件

	UninitAndDestroy(); // 取消初始化并销毁
}

/**
 * 取消初始化并销毁
 */
void ALyraCharacter::UninitAndDestroy()
{
	if (GetLocalRole() == ROLE_Authority) // 如果是权威角色
	{
		DetachFromControllerPendingDestroy(); // 从控制器分离等待销毁
		SetLifeSpan(0.1f); // 设置生命周期
	}

	// 如果我们仍然是化身Actor，则取消初始化ASC（否则另一个Pawn在成为化身Actor时已经做了）
	if (ULyraAbilitySystemComponent* LyraASC = GetLyraAbilitySystemComponent()) // 获取Lyra能力系统组件
	{
		if (LyraASC->GetAvatarActor() == this) // 如果化身Actor是this
		{
			PawnExtComponent->UninitializeAbilitySystem(); // 取消初始化能力系统
		}
	}

	SetActorHiddenInGame(true); // 在游戏中隐藏Actor
}

/**
 * 移动模式改变时调用
 */
void ALyraCharacter::OnMovementModeChanged(EMovementMode PrevMovementMode, uint8 PreviousCustomMode)
{
	Super::OnMovementModeChanged(PrevMovementMode, PreviousCustomMode); // 调用父类方法

	ULyraCharacterMovementComponent* LyraMoveComp = CastChecked<ULyraCharacterMovementComponent>(GetCharacterMovement()); // 获取Lyra角色移动组件

	SetMovementModeTag(PrevMovementMode, PreviousCustomMode, false); // 设置移动模式标签为false
	SetMovementModeTag(LyraMoveComp->MovementMode, LyraMoveComp->CustomMovementMode, true); // 设置移动模式标签为true
}

/**
 * 设置移动模式标签
 */
void ALyraCharacter::SetMovementModeTag(EMovementMode MovementMode, uint8 CustomMovementMode, bool bTagEnabled)
{
	if (ULyraAbilitySystemComponent* LyraASC = GetLyraAbilitySystemComponent()) // 获取Lyra能力系统组件
	{
		const FGameplayTag* MovementModeTag = nullptr; // 移动模式标签
		if (MovementMode == MOVE_Custom) // 如果是自定义移动模式
		{
			MovementModeTag = LyraGameplayTags::CustomMovementModeTagMap.Find(CustomMovementMode); // 从自定义移动模式标签映射中查找
		}
		else // 否则
		{
			MovementModeTag = LyraGameplayTags::MovementModeTagMap.Find(MovementMode); // 从移动模式标签映射中查找
		}

		if (MovementModeTag && MovementModeTag->IsValid()) // 如果移动模式标签存在且有效
		{
			LyraASC->SetLooseGameplayTagCount(*MovementModeTag, (bTagEnabled ? 1 : 0)); // 设置松散游戏标签计数
		}
	}
}

/**
 * 切换下蹲状态
 */
void ALyraCharacter::ToggleCrouch()
{
	const ULyraCharacterMovementComponent* LyraMoveComp = CastChecked<ULyraCharacterMovementComponent>(GetCharacterMovement()); // 获取Lyra角色移动组件

	if (IsCrouched() || LyraMoveComp->bWantsToCrouch) // 如果正在下蹲或想要下蹲
	{
		UnCrouch(); // 取消下蹲
	}
	else if (LyraMoveComp->IsMovingOnGround()) // 如果在地面上移动
	{
		Crouch(); // 下蹲
	}
}

/**
 * 开始下蹲时调用
 */
void ALyraCharacter::OnStartCrouch(float HalfHeightAdjust, float ScaledHalfHeightAdjust)
{
	if (ULyraAbilitySystemComponent* LyraASC = GetLyraAbilitySystemComponent()) // 获取Lyra能力系统组件
	{
		LyraASC->SetLooseGameplayTagCount(LyraGameplayTags::Status_Crouching, 1); // 设置下蹲状态标签计数为1
	}

	Super::OnStartCrouch(HalfHeightAdjust, ScaledHalfHeightAdjust); // 调用父类方法
}

/**
 * 结束下蹲时调用
 */
void ALyraCharacter::OnEndCrouch(float HalfHeightAdjust, float ScaledHalfHeightAdjust)
{
	if (ULyraAbilitySystemComponent* LyraASC = GetLyraAbilitySystemComponent()) // 获取Lyra能力系统组件
	{
		LyraASC->SetLooseGameplayTagCount(LyraGameplayTags::Status_Crouching, 0); // 设置下蹲状态标签计数为0
	}

	Super::OnEndCrouch(HalfHeightAdjust, ScaledHalfHeightAdjust); // 调用父类方法
}

/**
 * 检查是否可以跳跃内部实现
 */
bool ALyraCharacter::CanJumpInternal_Implementation() const
{
	// 与ACharacter的实现相同，但没有下蹲检查
	return JumpIsAllowedInternal(); // 返回是否允许跳跃内部
}

/**
 * 复制加速度改变时调用
 */
void ALyraCharacter::OnRep_ReplicatedAcceleration()
{
	if (ULyraCharacterMovementComponent* LyraMovementComponent = Cast<ULyraCharacterMovementComponent>(GetCharacterMovement())) // 获取Lyra角色移动组件
	{
		// 解压缩加速度
		const double MaxAccel         = LyraMovementComponent->MaxAcceleration; // 最大加速度
		const double AccelXYMagnitude = double(ReplicatedAcceleration.AccelXYMagnitude) * MaxAccel / 255.0; // [0, 255] -> [0, MaxAccel]
		const double AccelXYRadians   = double(ReplicatedAcceleration.AccelXYRadians) * TWO_PI / 255.0;     // [0, 255] -> [0, 2PI]

		FVector UnpackedAcceleration(FVector::ZeroVector); // 解压后的加速度
		FMath::PolarToCartesian(AccelXYMagnitude, AccelXYRadians, UnpackedAcceleration.X, UnpackedAcceleration.Y); // 极坐标转笛卡尔坐标
		UnpackedAcceleration.Z = double(ReplicatedAcceleration.AccelZ) * MaxAccel / 127.0; // [-127, 127] -> [-MaxAccel, MaxAccel]

		LyraMovementComponent->SetReplicatedAcceleration(UnpackedAcceleration); // 设置复制加速度
	}
}

/**
 * 设置通用团队ID
 */
void ALyraCharacter::SetGenericTeamId(const FGenericTeamId& NewTeamID)
{
	if (GetController() == nullptr) // 如果控制器为空
	{
		if (HasAuthority()) // 如果有权限
		{
			const FGenericTeamId OldTeamID = MyTeamID; // 获取旧团队ID
			MyTeamID = NewTeamID; // 设置新团队ID
			ConditionalBroadcastTeamChanged(this, OldTeamID, MyTeamID); // 条件广播团队改变
		}
		else // 否则
		{
			UE_LOG(LogLyraTeams, Error, TEXT("You can't set the team ID on a character (%s) except on the authority"), *GetPathNameSafe(this)); // 记录错误日志
		}
	}
	else // 否则
	{
		UE_LOG(LogLyraTeams, Error, TEXT("You can't set the team ID on a possessed character (%s); it's driven by the associated controller"), *GetPathNameSafe(this)); // 记录错误日志
	}
}

/**
 * 获取通用团队ID
 */
FGenericTeamId ALyraCharacter::GetGenericTeamId() const
{
	return MyTeamID; // 返回我的团队ID
}

/**
 * 获取团队索引改变委托
 */
FOnLyraTeamIndexChangedDelegate* ALyraCharacter::GetOnTeamIndexChangedDelegate()
{
	return &OnTeamChangedDelegate; // 返回团队改变委托
}

/**
 * 控制器改变团队时调用
 */
void ALyraCharacter::OnControllerChangedTeam(UObject* TeamAgent, int32 OldTeam, int32 NewTeam)
{
	const FGenericTeamId MyOldTeamID = MyTeamID; // 获取我的旧团队ID
	MyTeamID = IntegerToGenericTeamId(NewTeam); // 设置我的新团队ID
	ConditionalBroadcastTeamChanged(this, MyOldTeamID, MyTeamID); // 条件广播团队改变
}

/**
 * 我的团队ID复制时调用
 */
void ALyraCharacter::OnRep_MyTeamID(FGenericTeamId OldTeamID)
{
	ConditionalBroadcastTeamChanged(this, OldTeamID, MyTeamID); // 条件广播团队改变
}

/**
 * 更新共享复制
 */
bool ALyraCharacter::UpdateSharedReplication()
{
	if (GetLocalRole() == ROLE_Authority) // 如果是权威角色
	{
		FSharedRepMovement SharedMovement; // 共享复制移动
		if (SharedMovement.FillForCharacter(this)) // 如果为角色填充成功
		{
			// 只有当数据自上一帧以来发生变化时才调用FastSharedReplication。
			// 跳过此调用将导致复制重用我们先前产生的相同数据包，但不会发送给已经接收过的客户端。（但是尚未接收的新客户端将在本帧收到）
			if (!SharedMovement.Equals(LastSharedReplication, this)) // 如果不等于上次共享复制
			{
				LastSharedReplication = SharedMovement; // 设置上次共享复制
				SetReplicatedMovementMode(SharedMovement.RepMovementMode); // 设置复制移动模式

				FastSharedReplication(SharedMovement); // 快速共享复制
			}
			return true; // 返回true
		}
	}

	// 我们现在无法快速复制。不发送任何内容。
	return false; // 返回false
}

/**
 * 快速共享复制实现
 */
void ALyraCharacter::FastSharedReplication_Implementation(const FSharedRepMovement& SharedRepMovement)
{
	if (GetWorld()->IsPlayingReplay()) // 如果正在播放回放
	{
		return; // 返回
	}

	// 检查时间戳以拒绝旧的移动。
	if (GetLocalRole() == ROLE_SimulatedProxy) // 如果是模拟代理角色
	{
		// 时间戳
		SetReplicatedServerLastTransformUpdateTimeStamp(SharedRepMovement.RepTimeStamp); // 设置复制服务器最后变换更新时间戳

		// 移动模式
		if (GetReplicatedMovementMode() != SharedRepMovement.RepMovementMode) // 如果复制移动模式不等于共享复制移动模式
		{
			SetReplicatedMovementMode(SharedRepMovement.RepMovementMode); // 设置复制移动模式
			GetCharacterMovement()->bNetworkMovementModeChanged = true; // 设置网络移动模式已改变
			GetCharacterMovement()->bNetworkUpdateReceived = true; // 设置网络更新已接收
		}

		// 位置、旋转、速度等
		FRepMovement& MutableRepMovement = GetReplicatedMovement_Mutable(); // 获取可变复制移动
		MutableRepMovement = SharedRepMovement.RepMovement; // 设置复制移动

		// 这也设置了LastRepMovement
		OnRep_ReplicatedMovement(); // 调用复制移动改变

		// 跳跃力
		SetProxyIsJumpForceApplied(SharedRepMovement.bProxyIsJumpForceApplied); // 设置代理是否应用跳跃力

		// 下蹲
		if (IsCrouched() != SharedRepMovement.bIsCrouched) // 如果下蹲状态不等于共享复制下蹲状态
		{
			SetIsCrouched(SharedRepMovement.bIsCrouched); // 设置是否下蹲
			OnRep_IsCrouched(); // 调用下蹲状态改变
		}
	}
}

/**
 * FSharedRepMovement构造函数
 */
FSharedRepMovement::FSharedRepMovement()
{
	RepMovement.LocationQuantizationLevel = EVectorQuantization::RoundTwoDecimals; // 复制移动位置量化级别
}

/**
 * 为角色填充数据
 */
bool FSharedRepMovement::FillForCharacter(ACharacter* Character)
{
	if (USceneComponent* PawnRootComponent = Character->GetRootComponent()) // 如果Pawn根组件存在
	{
		UCharacterMovementComponent* CharacterMovement = Character->GetCharacterMovement(); // 获取角色移动组件

		RepMovement.Location = FRepMovement::RebaseOntoZeroOrigin(PawnRootComponent->GetComponentLocation(), Character); // 复制移动位置
		RepMovement.Rotation = PawnRootComponent->GetComponentRotation(); // 复制移动旋转
		RepMovement.LinearVelocity = CharacterMovement->Velocity; // 复制移动线性速度
		RepMovementMode = CharacterMovement->PackNetworkMovementMode(); // 复制移动模式
		bProxyIsJumpForceApplied = Character->GetProxyIsJumpForceApplied() || (Character->JumpForceTimeRemaining > 0.0f); // 代理是否应用跳跃力
		bIsCrouched = Character->IsCrouched(); // 是否下蹲

		// 如果未使用，时间戳作为零发送
		if ((CharacterMovement->NetworkSmoothingMode == ENetworkSmoothingMode::Linear) || CharacterMovement->bNetworkAlwaysReplicateTransformUpdateTimestamp) // 如果网络平滑模式为线性或总是复制变换更新时间戳
		{
			RepTimeStamp = CharacterMovement->GetServerLastTransformUpdateTimeStamp(); // 复制时间戳
		}
		else // 否则
		{
			RepTimeStamp = 0.f; // 复制时间戳为0
		}

		return true; // 返回true
	}
	return false; // 返回false
}

/**
 * 比较是否相等
 */
bool FSharedRepMovement::Equals(const FSharedRepMovement& Other, ACharacter* Character) const
{
	if (RepMovement.Location != Other.RepMovement.Location) // 如果位置不相等
	{
		return false; // 返回false
	}

	if (RepMovement.Rotation != Other.RepMovement.Rotation) // 如果旋转不相等
	{
		return false; // 返回false
	}

	if (RepMovement.LinearVelocity != Other.RepMovement.LinearVelocity) // 如果线性速度不相等
	{
		return false; // 返回false
	}

	if (RepMovementMode != Other.RepMovementMode) // 如果移动模式不相等
	{
		return false; // 返回false
	}

	if (bProxyIsJumpForceApplied != Other.bProxyIsJumpForceApplied) // 如果代理应用跳跃力不相等
	{
		return false; // 返回false
	}

	if (bIsCrouched != Other.bIsCrouched) // 如果下蹲状态不相等
	{
		return false; // 返回false
	}

	return true; // 返回true
}

/**
 * 网络序列化
 */
bool FSharedRepMovement::NetSerialize(FArchive& Ar, class UPackageMap* Map, bool& bOutSuccess)
{
	bOutSuccess = true; // 输出成功为true
	RepMovement.NetSerialize(Ar, Map, bOutSuccess); // 复制移动网络序列化
	Ar << RepMovementMode; // 序列化移动模式
	Ar << bProxyIsJumpForceApplied; // 序列化代理是否应用跳跃力
	Ar << bIsCrouched; // 序列化是否下蹲

	// 时间戳，如果非零
	uint8 bHasTimeStamp = (RepTimeStamp != 0.f); // 是否有时间戳
	Ar.SerializeBits(&bHasTimeStamp, 1); // 序列化是否有时间戳
	if (bHasTimeStamp) // 如果有时间戳
	{
		Ar << RepTimeStamp; // 序列化时间戳
	}
	else // 否则
	{
		RepTimeStamp = 0.f; // 时间戳设为0
	}

	return true; // 返回true
}